Exploración de ofertas relámpago

¶

image-3.png

Las ofertas relámpago, de acuerdo con la fuente oficial de la guía para vendedores en Mercado Libre, nos indica que estas ofertas son realizadas con el objetivo de liquidar el stock que el vendedor tiene de sus productos en un lapso de 6 horas ofreciendo un descuento a los compradores en la página.

Teniendo información de más de 48mil ofertas que ocurrieron entre el 1 jun de 2021 y el 31 jul 2021, realizamos un análisis exploratorio que nos permitió entender asociaciones relevantes entre variables y llegar a conclusiones como:

  • Las mayores cantidades de ventas en ofertas relámpago son realizadas de Lunes a Viernes
  • Las ofertas relámpago coinciden con el contexto social, siendo los tapabocas y mascarillas faciales los más comunes entre los 1266 dominios

Que a su vez pueden convertirse en accionables e ideas para mejorar como se detallará a lo largo del notebook.

Los pasos desarrollados para el análisis exploratorio fueron los siguientes:

  • Importación de librerías y carga de información
  • Descubrimientos e hipótesis
  • Validación a través del análisis exploratorio
  • Conclusiones y recomendaciones finales

Librerías y carga de información¶

In [1]:
#!pip install itables
#!pip install plotly
In [2]:
from itables import init_notebook_mode
import pandas as pd
import plotly.graph_objects as go
import seaborn as sns
import matplotlib.pyplot as plt

init_notebook_mode(all_interactive=True)
In [3]:
ofertas_relampago = pd.read_csv ("C:/Users/Garzonm1/Desktop/Teste Técnico - DS/ofertas_relampago.csv")
In [4]:
ofertas_relampago.head(100)
Out[4]:
OFFER_START_DATE OFFER_START_DTTM OFFER_FINISH_DTTM OFFER_TYPE INVOLVED_STOCK REMAINING_STOCK_AFTER_END SOLD_AMOUNT SOLD_QUANTITY ORIGIN SHIPPING_PAYMENT_TYPE DOM_DOMAIN_AGG1 VERTICAL DOMAIN_ID
Loading... (need help?)

Observaciones e hipótesis iniciales¶

  • Observaciones
  1. La variable de offer_type no agrega valor adicional al análisis dado que es la que nos muestra que efectivamente sólo estamos analizando ofertas de tipo relámpago
  2. Existencia de stock remanente negativo: Esta variable puede ser el resultado del stock establecido para la oferta menos la cantidad de ventas que se detectaron, sin embargo cabe preguntarse: ¿Se realizaron de manera efectiva las ventas en negativo? ¿De donde se obtiene este número? para así entender el impacto que pueden llegar a tener en Mercado Libre en términos de devoluciones y para el vendedor con sus inventarios y producto.
  3. Las variables de SOLD_AMOUNT y SOLD_QUANTITY, parecen estar muy relacionadas entre sí y además tener valores vacíos para los mismos registros
  4. En la variable origin se encuentra más información vacía que propiamente explicativa del origen en la oferta relámpago
  • Hipótesis
  1. La fecha en la que se realiza la oferta es importante al momento de considerar las ventas (análisis más profundos con la hora de la oferta)
  2. La duración de la oferta se ve afectada por la cantidad de unidades en stock
  3. Existen categorías con muchas ofertas y poca venta
  4. Minimizar ausencia de ventas en ofertas es de interés para Mercado Libre y los vendedores (Cuando hay ausencia de ventas?)

Validar las hipótesis nos permitirá realizar un análisis exploratorio más profundo de las ofertas relámpago, sin ambargo antes de ello haremos un pequeño trabajo de limpieza y entendimiento de valores faltantes:

In [5]:
# Observar los campos, su tipo de dato y número de valores no nulos
ofertas_relampago.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 48746 entries, 0 to 48745
Data columns (total 13 columns):
 #   Column                     Non-Null Count  Dtype  
---  ------                     --------------  -----  
 0   OFFER_START_DATE           48746 non-null  object 
 1   OFFER_START_DTTM           48746 non-null  object 
 2   OFFER_FINISH_DTTM          48746 non-null  object 
 3   OFFER_TYPE                 48746 non-null  object 
 4   INVOLVED_STOCK             48746 non-null  int64  
 5   REMAINING_STOCK_AFTER_END  48746 non-null  int64  
 6   SOLD_AMOUNT                24579 non-null  float64
 7   SOLD_QUANTITY              24579 non-null  float64
 8   ORIGIN                     11316 non-null  object 
 9   SHIPPING_PAYMENT_TYPE      48746 non-null  object 
 10  DOM_DOMAIN_AGG1            48746 non-null  object 
 11  VERTICAL                   48746 non-null  object 
 12  DOMAIN_ID                  48746 non-null  object 
dtypes: float64(2), int64(2), object(9)
memory usage: 4.8+ MB
In [6]:
# Convertir las variables a los tipos adecuados

ofertas_relampago["OFFER_START_DATE"] = pd.to_datetime(ofertas_relampago["OFFER_START_DATE"], format='%Y-%m-%d')
ofertas_relampago["OFFER_START_DTTM"] = pd.to_datetime(ofertas_relampago["OFFER_START_DTTM"], format='%Y-%m-%d %H:%M:%S%z')
ofertas_relampago["OFFER_FINISH_DTTM"] = pd.to_datetime(ofertas_relampago["OFFER_FINISH_DTTM"], format='%Y-%m-%d %H:%M:%S%z')


ofertas_relampago['OFFER_TYPE']=ofertas_relampago['OFFER_TYPE'].astype('category')
ofertas_relampago['ORIGIN']=ofertas_relampago['ORIGIN'].astype('category')
ofertas_relampago['SHIPPING_PAYMENT_TYPE']=ofertas_relampago['SHIPPING_PAYMENT_TYPE'].astype('category')
ofertas_relampago['DOM_DOMAIN_AGG1']=ofertas_relampago['DOM_DOMAIN_AGG1'].astype('category')
ofertas_relampago['VERTICAL']=ofertas_relampago['VERTICAL'].astype('category')
ofertas_relampago['DOMAIN_ID']=ofertas_relampago['DOMAIN_ID'].astype('category')
In [7]:
# Función para realizar gráfico de barras en las columnas de un DataFrame
def plot_categorical_variables(df):
    # Select only categorical columns
    categorical_columns = df.select_dtypes(include=['object', 'category']).columns

    # Plot bar charts for each categorical column
    for column in categorical_columns:
        plt.figure(figsize=(10, 6))
        df[column].value_counts().plot(kind='bar', color='skyblue', edgecolor='black')
        plt.title(f'Bar Plot for {column}')
        plt.xlabel(column)
        plt.ylabel('Count')
        plt.show()

Valores Faltantes¶

Vemos en la información que para las variables SOLD_AMOUNT, SOLD_QUANTITY y ORIGIN el conteo de "no nulos" representa una falta de información importante para estas variables. Vamos a analizarla un poco más en detalle.

In [8]:
#Gráfica para visualizar la cantidad de faltantes por variable

# Calcular porcentajes de valores nulos para cada variable
total_rows = len(ofertas_relampago)
null_percentage_sold_amount = (ofertas_relampago['SOLD_AMOUNT'].isnull().sum() / total_rows) * 100
null_percentage_sold_quantity = (ofertas_relampago['SOLD_QUANTITY'].isnull().sum() / total_rows) * 100
null_percentage_origin = (ofertas_relampago['ORIGIN'].isnull().sum() / total_rows) * 100

# Crear un nuevo conjunto con esta información de nulos
data = {
    'Variables': ['SOLD_AMOUNT', 'SOLD_QUANTITY', 'ORIGIN'],
    'Porcentaje de Valores Nulos': [null_percentage_sold_amount, null_percentage_sold_quantity, null_percentage_origin],
}

df_percentage = pd.DataFrame(data)

# Crear el gráfico
fig = go.Figure()

fig.add_trace(go.Bar(
    x=df_percentage['Variables'],
    y=df_percentage['Porcentaje de Valores Nulos'],
    text=df_percentage['Porcentaje de Valores Nulos'].round(2).astype(str) + '%',
    textposition='auto',
    marker_color='lightblue',  # Puedes ajustar el color de las barras
))

# Ajustar detalles visuales
fig.update_layout(title='Porcentaje de Valores Nulos en Variables',
                  xaxis_title='Variables',
                  yaxis_title='Porcentaje de Nulos',
                  showlegend=False) 

fig.show()

En las ofertas relámpago, sucede que más del 75% de ellas no tienen una categoría de "ORIGIN" definida, y el restante porcentaje tiene una categoría "A", por lo cual en este caso es mejor convertir estos nulos en una categoría de "NO DEFINIDO" para facilitar el entendimiento y posibles asociaciones con otras variables.

In [9]:
#Reemplazar los nulos de ORIGIN por "NO DEFINIDO"
ofertas_relampago['ORIGIN'] = ofertas_relampago['ORIGIN'].cat.add_categories('NO DEFINIDO')
ofertas_relampago['ORIGIN'].fillna('NO DEFINIDO', inplace=True)

#Usar la funcion para ver la nueva forma de la variable
df = pd.DataFrame(ofertas_relampago["ORIGIN"])
plot_categorical_variables(df)

También llama la atención de los valores nulos que sea la misma cantidad de faltantes en ambas variables de ventas, si bien en los primeros registros se observó que cuando falta un dato en SOLD_AMOUNT, también falta en SOLD_QUANTITY, será validado con un cruce entre estas dos variables.

In [10]:
# Crear una tabla de contingencia
contingency_table = pd.crosstab(ofertas_relampago['SOLD_AMOUNT'].isnull(), ofertas_relampago['SOLD_QUANTITY'].isnull(), margins=True, margins_name="Total")

# Calcular los porcentajes
total_columns = contingency_table.iloc[:, -1]
contingency_table_percent = contingency_table.div(total_columns) * 100

formatted_table = contingency_table.astype(str) + '\n(' + contingency_table_percent.round(2).astype(str) + '%)'

# Crear la matriz 
plt.figure(figsize=(8, 5))
ax = sns.heatmap(contingency_table, annot=formatted_table, fmt='', cmap='Blues', cbar=False, linewidths=.5, annot_kws={"size": 12, "weight": "bold"})

# Ajustar el diseño de la figura
plt.title('Valores Nulos en SOLD_AMOUNT y SOLD_QUANTITY', fontsize=18)
plt.xlabel('SOLD_QUANTITY es Null', fontsize=14)
plt.ylabel('SOLD_AMOUNT es Null', fontsize=14)


plt.show()

Efectivamente, como mencionamos en las observaciones iniciales, la información faltante para ambas variables se encuentra en los mismos registros. Para no incurrir en la pérdida de casi el 50% de información, una técnica comunmente usada es la imputación de la media de estas variables en sus valores vacíos. Sin embargo, este enfoque afectaría la distribución por el alto volumen de faltantes.

Dado lo anterior, nos adentraremos en las hipótesis para entender en el contexto del negocio estos faltantes en las ofertas relámpago y ver si pueden ser explicados a través de otros campos.

Hipótesis¶

La validación de las hipótesis mencionadas al inicio nos ayudará a comprender desde el análisis exploratorio las variables del conjunto para las ofertas relámpago y además de ello permitirá proponer algunos accionables de interés para el negocio

1. La fecha en la que se realiza la oferta es importante al momento de considerar las ventas¶

In [12]:
#Primero ubicarnos en el tiempo

# Obtener el conteo de filas en cada fecha
conteos = ofertas_relampago['OFFER_START_DATE'].value_counts().reset_index()
conteos.columns = ['OFFER_START_DATE', 'Conteo']

# Ordenar el DataFrame por la columna de fechas
conteos = conteos.sort_values(by='OFFER_START_DATE')

# Crear el gráfico de líneas con puntos
fig = go.Figure()

fig.add_trace(go.Scatter(x=conteos['OFFER_START_DATE'], y=conteos['Conteo'], mode='markers+lines', name='Conteo'))

# Establecer el diseño del gráfico
fig.update_layout(title='Línea de Tiempo vs Numero de ofertas relámpago',
                  xaxis_title='Fecha',
                  yaxis_title='Ofertas relámpago',
                  showlegend=False)

# Mostrar el gráfico
fig.show()

De entrada vemos que contamos información de dos meses completos entre Junio 1° y Julio 31 de 2021. Lo anterior nos permite ubicarnos en un contexto global, donde la pandemia por el COVID-19 nos tenía en alerta , y países como México se preparaban para una nueva ola como muestra su registro histórico de casos confirmados:

image.png

Ahora, llevando lo anterior al contexto de las ofertas relámpago en Mercado Libre ¿Qué sucedió el 30 de jun 2021 y el 1 jul 2021?. Se observa la caída importante justo el último día del mes de junio e inmediatamente despúes una subida que cuadriplica el número de ofertas del 30 de junio en menos de una semana, probablemente los vendedores se preparaban para unos días de ofertas de verano en este periodo.

In [13]:
#Ahora veamos las cantidades de venta en estas fechas

conteos = ofertas_relampago.groupby('OFFER_START_DATE')['SOLD_QUANTITY'].sum().reset_index()

# Ordenar el DataFrame por la columna de fechas
conteos = conteos.sort_values(by='OFFER_START_DATE')

# Crear el gráfico de líneas con puntos
fig = go.Figure()

fig.add_trace(go.Scatter(x=conteos['OFFER_START_DATE'], y=conteos['SOLD_QUANTITY'], mode='markers+lines', name='SOLD_QUANTITY'))

# Establecer el diseño del gráfico
fig.update_layout(title='Línea de Tiempo vs Cantidad Vendida',
                  xaxis_title='Fecha',
                  yaxis_title='Cantidad Vendida',
                  showlegend=False)

# Mostrar el gráfico
fig.show()

Pese a la mencionada falta de información en esta variable, podemos ver una estacionariedad en la serie de manera semanal donde el fin de semana parece ser los días de la semana con menos cantidad de ventas.

Resultados y recomendaciones¶

Independientemente de la cantidad de ofertas que existan en la plataforma, las ventas asociadas a ellas parecen estar sujetas más hacia el día de la semana en el que se realiza.

Una estrategia accionable para el marketplace de Mercado Libre enfocada a los vendedores sería suministrar este servicio de asesoría o guía, incluso desagregada de acuerdo con los productos que tiene elegibles para ofertas y apoyar la toma de decisiones frente a qué día lanzar la oferta.

Otra opción pensando en incentivar la venta en fines de semana podría ser una categoría especial de descuentos relámpago mayor para estos días.

Como análisis adicional propuesto se recomienda hacer un doble click en la hora del día en la cual se da la oferta para entender el comportamiento de compradores y promover night deals o madrugón según el caso

2. La duración de la oferta se ve afectada por la cantidad de unidades en stock¶

Si bien las ofertas relámpago tienen una duración establecida de 6 horas, lo primero que haremos es validar por qué algunas dentro de los primeros registros observados tienen una duracion distinta a este tiempo.

3. Existen categorías con muchas ofertas y poca venta¶

El primer paso para explorar esta hipótesis se encuentra en entender las diferencias que existen entre las tres variables que explican las categorías de productos como son la vertical, el dominio agregado y el dominio id.

In [14]:
# Ver cantidades de clases en cada una de las variables

# Obtener todos los valores únicos de las columnas "VERTICAL", "DOM_DOMAIN_AGG1" y "DOMAIN_ID"
vertical_values = ofertas_relampago["VERTICAL"].unique()
dom_domain_values = ofertas_relampago["DOM_DOMAIN_AGG1"].unique()
domain_id_values = ofertas_relampago["DOMAIN_ID"].unique()


conteo_categorias = pd.DataFrame({
    'Variable': ['VERTICAL', 'DOM_DOMAIN_AGG1', 'DOMAIN_ID'],
    'Cantidad de Categorías': [len(vertical_values), len(dom_domain_values), len(domain_id_values)]
})

conteo_categorias
Out[14]:
Variable Cantidad de Categorías
Loading... (need help?)

Lo anterior muestra que "vertical" corresponde a una familia grande de productos, de donde se desprenden los dominios agregados y de allí a su vez los dominios ID. Visualizaremos mejor esta relación y unirla con la cantidad de ofertas en cada una de ellas a continuación:

In [15]:
#Creación del diagrama sankey para las tres variables con el número de ofertas

# Unir todas las listas de valores para hacer los nodos del diagrama
node_label = list(vertical_values) + list(dom_domain_values) + list(domain_id_values)
In [16]:
node_dict = {y:x for x, y in enumerate(node_label)}
In [17]:
# Seleccionar las columnas para relacionar
columnas_interes = ["VERTICAL", "DOM_DOMAIN_AGG1"]

# Crear una nueva DataFrame con las columnas seleccionadas
tabla_relaciones = ofertas_relampago[columnas_interes].copy()

# Convertir columnas
tabla_relaciones.loc[:, "VERTICAL"] = tabla_relaciones["VERTICAL"].astype(str)
tabla_relaciones.loc[:, "DOM_DOMAIN_AGG1"] = tabla_relaciones["DOM_DOMAIN_AGG1"].astype(str)

# Contar la cantidad de veces que se relaciona un elemento de VERTICAL con uno de DOM_DOMAIN_AGG1
conteo_relaciones = tabla_relaciones.groupby(["VERTICAL", "DOM_DOMAIN_AGG1"]).size().reset_index(name="value")

# Renombrar las columnas
conteo_relaciones.columns = ["source", "target", "values"]

# Ordenar de mayor a menor y eliminar filas sin relación
conteo_relaciones = conteo_relaciones.sort_values(by="values", ascending=False)
conteo_relaciones = conteo_relaciones[conteo_relaciones["values"] != 0]

conteo_relaciones1 = conteo_relaciones
In [18]:
# Seleccionar las otras dos columnas para evaluar relación
columnas_interes = ["DOM_DOMAIN_AGG1","DOMAIN_ID"]

# Crear DataFrame con columnas seleccionadas
tabla_relaciones = ofertas_relampago[columnas_interes].copy()

# Convertir columnas
tabla_relaciones.loc[:, "DOM_DOMAIN_AGG1"] = tabla_relaciones["DOM_DOMAIN_AGG1"].astype(str)
tabla_relaciones.loc[:, "DOMAIN_ID"] = tabla_relaciones["DOMAIN_ID"].astype(str)

# Conteo de relaciones
conteo_relaciones = tabla_relaciones.groupby(["DOM_DOMAIN_AGG1","DOMAIN_ID"]).size().reset_index(name="values")
conteo_relaciones.columns = ["source", "target", "values"]

# Ordenar de mayor a menor y eliminar filas sin relación existente
conteo_relaciones = conteo_relaciones.sort_values(by="values", ascending=False)
conteo_relaciones = conteo_relaciones[conteo_relaciones["values"] != 0]

conteo_relaciones2 = conteo_relaciones
In [19]:
# Concatenar los DataFrames
conteo_relaciones_concatenado = pd.concat([conteo_relaciones1, conteo_relaciones2], ignore_index=True)
conteo_relaciones_concatenado
Out[19]:
source target values
Loading... (need help?)
In [20]:
# Convertir en listas
source = conteo_relaciones_concatenado["source"].tolist()
target = conteo_relaciones_concatenado["target"].tolist()
values = conteo_relaciones_concatenado["values"].tolist()
In [21]:
source_node = [node_dict[x] for x in source]
target_node = [node_dict[x] for x in target]
In [22]:
# Obtener colores únicos para cada categoría de origen
unique_source_nodes = list(set(source_node))
num_unique_nodes = len(unique_source_nodes)
colors = [f"hsla({idx * (360 // num_unique_nodes)}, 50%, 50%, 0.5)" for idx in range(num_unique_nodes)]

# Asignar colores a los nodos y enlaces
node_colors = [colors[unique_source_nodes.index(src)] for src in source_node]
link_colors = [colors[unique_source_nodes.index(src)] for src in source_node]

# Crear el objeto Figura
fig = go.Figure(
    data=[go.Sankey(
        node=dict(
            pad=15,
            thickness=20,
            line=dict(color='black', width=0.5),
            label=node_label,
            color=node_colors  # Asignar colores basados en la categoría de origen
        ),
        link=dict(
            source=source_node,
            target=target_node,
            value=values,
            color=link_colors  # Asignar colores basados en la categoría de origen
        ))])

# Establecer el diseño para que el gráfico sea más fácil de leer
fig.update_layout(font_size=7,
                  autosize=True,
                  width=800,
                  height=5000)

# Mostrar el gráfico
fig.show()

Lo primero que salta a la vista es que podemos comprobar la pertenencia de las verticales como clases agrupadoras de dominios agregados y estas a su vez cumplen la misma función con los dominios ID.

En cuanto a verticales, sin duda App & Sports y Home and Industry son ganadoras en número de ofertas

Resultados y recomendaciones¶

Viendo la relación entre verticales, y la cantidad de ofertas que puede ser muy baja en algunas de ellos, pueden recomendarse estrategias para tener días de ofertas por verticales (e.g. Lunes de Deportes, Martes de Hogar, etc), esto con el fin de incentivar las ofertas y por ende conversiones en categorías pequeñas.

Construcción de un indicador por vertical, por dominio agregado y dominio específico, que muestre la relación entre el numero de ofertas y el número de ventas para medir su efectividad y realizar seguimiento para determinar una futura probabilidad de éxito en la siguiente oferta que aplique.

Garantizar en las ofertas del día un balanceo entre las diferentes categorías, para que todas ellas tengan visibilidad sin importar el tamaño de su categoría

Definir las políticas de elegibilidad para los productos en estas ofertas de MercadoLibre de manera constante con base a los indicadores propuestos.

4. Minimizar ausencia de ventas en ofertas es de interés para Mercado Libre y los vendedores¶

El objetivo final tanto de Mercado Libre como del vendedor es generar la venta a través de la plataforma, para el caso de las ofertas relámpago, podemos definir alguna estrategia que permita maximizar las probabilidades de vender el producto en ese periodo de tiempo según ciertas variables, ya hemos visto la relacion de las ventas con otras variables. Sin embargo, no hemos identificado las ofertas que NO generan ventas.

In [24]:
ofertas_relampago.describe()
Out[24]:
OFFER_START_DATE INVOLVED_STOCK REMAINING_STOCK_AFTER_END SOLD_AMOUNT SOLD_QUANTITY
Loading... (need help?)

Si el minimo de cantidad vendida es 1, sugiere que todos los item tuvieron venta durante la oferta, sin embargo no contempla los valores NaN que parecen estar vacíos cuando no existe venta, según lo observado en los primeros registros.

A pesar de que los valores de ventan llaman la atencion por ser números tan pequeños, puede deberse a alguna transformación previa realizada a los datos y veremos su relación que es aprentemente clara con la cantidad.

En el stock al finalizar la oferta es extraño que queden valores negativos y el valor maximo parece ser un outlier que ya comprobaremos.

In [25]:
#Realizar histogramas para entender la distribución de variables numéricas

ofertas_relampago_num = ofertas_relampago

for column in ofertas_relampago:
    if ofertas_relampago[column].dtype != 'float64' and ofertas_relampago[column].dtype != 'int64':
        #Add column to df_numerical_client
        ofertas_relampago_num=ofertas_relampago_num.drop(f'{column}',axis=1)


ofertas_relampago_num.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 48746 entries, 0 to 48745
Data columns (total 4 columns):
 #   Column                     Non-Null Count  Dtype  
---  ------                     --------------  -----  
 0   INVOLVED_STOCK             48746 non-null  int64  
 1   REMAINING_STOCK_AFTER_END  48746 non-null  int64  
 2   SOLD_AMOUNT                24579 non-null  float64
 3   SOLD_QUANTITY              24579 non-null  float64
dtypes: float64(2), int64(2)
memory usage: 1.5 MB
In [26]:
def multiple_boxplots (dataframe):

    columns_to_plot = dataframe.columns

    fig, axs = plt.subplots(nrows=len(columns_to_plot), figsize=(18, 5 * len(columns_to_plot)))

    for i, column in enumerate(columns_to_plot):
        sns.boxplot(x=dataframe[column], ax=axs[i])
        axs[i].ticklabel_format(style='plain', axis='x')
        axs[i].set_title(f'Boxplot for {column}')


    plt.tight_layout()
    plt.show()
In [27]:
multiple_boxplots(ofertas_relampago_num)

Los histogramas para estas variables nos confirman su concentración hacia valores muy bajos pese

In [28]:
# Calcular la matriz de correlación
correlation_matrix = ofertas_relampago_num.corr()

# Crear el corr plot con seaborn
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', fmt=".2f", linewidths=.5, vmin=-1, vmax=1)
plt.title('Correlación entre Variables de Fallas', fontsize=16)
plt.show()

De esta matriz comprobamos la relación lineal existente entre las variables de stock y las variables de ventas entre sí. Con este resultado, se debe manejar de manera cuidadosa si se quieren ser usadas para algún modelo analítico ya que puede generar mucho ruido agregar todas ellas.

Conclusiones y recomendaciones¶

  • Construir nuevas variables: Tiempo duración de oferta en horas, price unit basado en el valor de ventas y sus unidades para identificar otras relaciones menos evidentes en el conjunto.

  • Evaluar la relación entre las ofertas que duraron menos de las seis horas con la cantidad de stock, esta relación puede generar una alerta al vendedor que le informa acerca del agotamiento de su stock, permitiendo modificarlo para continuar con la oferta en el tiempo restante.